﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Borg.AttributeAnalyze;
using Borg.AttributeAnalyze.Result;
using Properties;

namespace Borg
{
    public class SlotTypeInfo : RepositoryMetaElement
    {
        internal static int nextId = 1;

        internal static QualificationState unqualifiedState =
            QualificationState.QualificationMissing |
            QualificationState.SlotNameAlreadyExists |
            QualificationState.SlotSlotDefinitionNotFound;

        internal static QualificationState warningState =
            QualificationState.SlotOnOpeningMethodNotFound |
            QualificationState.SlotOnOpenedMethodNotFound |
            QualificationState.SlotOnClosingMethodNotFound |
            QualificationState.SlotOnClosedMethodNotFound |
            QualificationState.SlotOnRegisteringMethodNotFound |
            QualificationState.SlotOnRegisteredMethodNotFound |
            QualificationState.SlotOnDeregisteringMethodNotFound |
            QualificationState.SlotOnDeregisteredMethodNotFound |
            QualificationState.SlotOnPluggingMethodNotFound |
            QualificationState.SlotOnPluggingCanceledMethodNotFound |
            QualificationState.SlotOnPluggedMethodNotFound |
            QualificationState.SlotOnUnpluggingMethodNotFound |
            QualificationState.SlotOnUnpluggedMethodNotFound |
            QualificationState.SlotOnSelectionChangedMethodNotFound;

        internal readonly SlotAttribute slotAttribute;
        internal ExtensionTypeInfo extensionTypeInfo;
        internal SlotDefinition slotDefinition;

        internal bool eventHandlerMethodInfosSet;

        internal MethodInfo MiOnOpening;
        internal MethodInfo MiOnOpened;

        internal MethodInfo MiOnClosing;
        internal MethodInfo MiOnClosed;

        internal MethodInfo MiOnRegistering;
        internal MethodInfo MiOnRegistered;

        internal MethodInfo MiOnDeregistering;
        internal MethodInfo MiOnDeregistered;

        internal MethodInfo MiOnPlugging;
        internal MethodInfo MiOnPluggingCanceled;
        internal MethodInfo MiOnPlugged;

        internal MethodInfo MiOnUnplugging;
        internal MethodInfo MiOnUnplugged;

        internal MethodInfo MiOnSelectionChanged;

        public event CancelRegisterEventHandler Registering;
        public event RegisterEventHandler Registered;

        public event CancelRegisterEventHandler Deregistering;
        public event RegisterEventHandler Deregistered;

        public event CancelPlugEventHandler Plugging;
        public event CancelPlugEventHandler PluggingCanceled;
        public event PlugEventHandler Plugged;

        public event CancelPlugEventHandler Unplugging;
        public event PlugEventHandler Unplugged;

        public event CancelSlotEventHandler Opening;
        public event SlotEventHandler Opened;

        public event CancelSlotEventHandler Closing;
        public event SlotEventHandler Closed;

        public event SelectionChangedEventHandler SelectionChanged;

        private readonly string _name;

        public override string Name
        {
            get { return _name; }
        }

        public override Assembly Assembly
        {
            get { return extensionTypeInfo.pluginInfo.assembly; }
        }

        public bool AutoOpen
        {
            get { return slotAttribute.AutoOpen; }
            set
            {
                if (!Runtime.IsCompositionAllowed)
                    throw new InvalidOperationException("Composition not allowed");

                Runtime.Composer.SetAutoOpen(this, value);
            }
        }

        public bool AutoRegister
        {
            get { return slotAttribute.AutoRegister; }
            set
            {
                if (!Runtime.IsCompositionAllowed)
                    throw new InvalidOperationException("Composition not allowed");

                Runtime.Composer.SetAutoRegister(this, value);
            }
        }

        public bool AutoPlug
        {
            get { return slotAttribute.AutoPlug; }
            set
            {
                if (!Runtime.IsCompositionAllowed)
                    throw new InvalidOperationException("Composition not allowed");

                Runtime.Composer.SetAutoPlug(this, value);
            }
        }

        public bool LazyLoad
        {
            get { return slotAttribute.LazyLoad; }
            set
            {
                if (!Runtime.IsCompositionAllowed)
                    throw new InvalidOperationException("Composition not allowed");

                Runtime.Composer.SetLazyLoad(this, value);
            }
        }

        public bool Multiple
        {
            get { return slotAttribute.Multiple; }
            set
            {
                if (!Runtime.IsCompositionAllowed)
                    throw new InvalidOperationException("Composition not allowed");

                Runtime.Composer.SetMultiple(this, value);
            }
        }

        public bool Unique
        {
            get { return slotAttribute.Unique; }
            set
            {
                if (!Runtime.IsCompositionAllowed)
                    throw new InvalidOperationException("Composition not allowed");

                Runtime.Composer.SetUnique(this, value);
            }
        }

        public bool AutoRelease
        {
            get { return slotAttribute.AutoRelease; }
            set
            {
                if (!Runtime.IsCompositionAllowed)
                    throw new InvalidOperationException("Composition not allowed");

                Runtime.Composer.SetAutoRelease(this, value);
            }
        }

        public SelectionMode SelectionMode
        {
            get { return slotAttribute.SelectionMode; }
            set
            {
                if (!Runtime.IsCompositionAllowed)
                    throw new InvalidOperationException("Composition not allowed");

                Runtime.Composer.SetSelectionMode(this, value);
            }
        }

        public IEnumerable<KeyValuePair<string, string>> EventHandlers
        {
            get
            {
                yield return new KeyValuePair<string, string>("OnOpening", slotAttribute.OnOpening);
                yield return new KeyValuePair<string, string>("OnOpened", slotAttribute.OnOpened);

                yield return new KeyValuePair<string, string>("OnClosing", slotAttribute.OnClosing);
                yield return new KeyValuePair<string, string>("OnClosed", slotAttribute.OnClosed);

                yield return new KeyValuePair<string, string>("OnRegistering", slotAttribute.OnRegistering);
                yield return new KeyValuePair<string, string>("OnRegistered", slotAttribute.OnRegistered);

                yield return new KeyValuePair<string, string>("OnDeregistering", slotAttribute.OnDeregistering);
                yield return new KeyValuePair<string, string>("OnDeregistered", slotAttribute.OnDeregistered);

                yield return new KeyValuePair<string, string>("OnPlugging", slotAttribute.OnPlugging);
                yield return new KeyValuePair<string, string>("OnPluggingCanceled", slotAttribute.OnPluggingCanceled);
                yield return new KeyValuePair<string, string>("OnPlugged", slotAttribute.OnPlugged);

                yield return new KeyValuePair<string, string>("OnUnplugging", slotAttribute.OnUnplugging);
                yield return new KeyValuePair<string, string>("OnUnplugged", slotAttribute.OnUnplugged);

                yield return new KeyValuePair<string, string>("OnSelectionChanged", slotAttribute.OnSelectionChanged);
            }
        }

        public SlotDefinition SlotDefinition
        {
            get
            {
                if (slotDefinition == null)
                    throw new InvalidOperationException("Slot is not qualified");

                return slotDefinition;
            }
        }

        public string DerivedFrom
        {
            get { return slotAttribute.DerivedFrom; }
        }

        public override bool IsQualified
        {
            get { return (qualificationState & unqualifiedState) == QualificationState.None; }
        }

        public ExtensionTypeInfo ExtensionTypeInfo
        {
            get { return extensionTypeInfo; }
        }

        static SlotTypeInfo()
        { }

        internal SlotTypeInfo(ExtensionTypeInfo extensionTypeInfo, SlotAttribute slotAttribute)
        {
            id = nextId++;
            this.slotAttribute = slotAttribute;
            _name = slotAttribute.Name;
            this.extensionTypeInfo = extensionTypeInfo;
        }

        internal override QualificationState InternalQualify()
        {
            InternalMainQualify();

            return IsQualified
                ? VerifyEventHandlerMethods(true)
                : qualificationState;
        }

        internal QualificationState InternalMainQualify()
        {
            var builder = new StringBuilder();
            slotDefinition = Runtime.Repository.GetQualifiedSlotDefinition(Name);

            if (slotDefinition == null)
            {
                if (slotAttribute.DerivedFrom != string.Empty)
                {
                    var qualifiedSlotDefinition =
                        Runtime.Repository.GetQualifiedSlotDefinition(slotAttribute.DerivedFrom);

                    if (qualifiedSlotDefinition == null)
                    {
                        builder.AppendFormat("\n  {0}", Messages.SlotDefinitionNotFound);
                        var slotTypeInfo = this;
                        var state = (long)(slotTypeInfo.qualificationState | QualificationState.SlotSlotDefinitionNotFound);
                        slotTypeInfo.qualificationState = (QualificationState)state;
                    }
                    else
                        slotDefinition = Runtime.Repository.CreateSlotDefinition(Name, qualifiedSlotDefinition);
                }
                else
                {
                    builder.AppendFormat("\n  {0}", Messages.SlotDefinitionNotFound);
                    var slotTypeInfo = this;
                    var state = (long)(slotTypeInfo.qualificationState | QualificationState.SlotSlotDefinitionNotFound);
                    slotTypeInfo.qualificationState = (QualificationState)state;
                }
            }
            else
            {
                var sti = this;
                var state = (long)(sti.qualificationState & ~QualificationState.SlotSlotDefinitionNotFound);
                sti.qualificationState = (QualificationState)state;

                if (extensionTypeInfo.slotTypeInfos.
                    Any(slotType => slotType != this &&
                        slotType.Name == Name && slotType.IsQualified))
                {
                    builder.AppendFormat("\n  {0}", Messages.SlotAlreadyExists);
                    var slotTypeInfo = this;
                    var stat = (long)(slotTypeInfo.qualificationState | QualificationState.SlotNameAlreadyExists);
                    slotTypeInfo.qualificationState = (QualificationState)stat;
                }
            }

            var slotTyp = this;
            var stt = (long)(slotTyp.qualificationState & ~QualificationState.QualificationMissing);
            slotTyp.qualificationState = (QualificationState)stt;

            RuntimeBase.LogQualifyResult(
                this,
                qualificationState,
                unqualifiedState,
                warningState,
                Messages.QualifySlot,
                builder.ToString());

            return qualificationState;
        }

        internal QualificationState VerifyEventHandlerMethods(bool logResult)
        {
            return VerifyEventHandlerMethods(logResult, null);
        }

        internal QualificationState VerifyEventHandlerMethods(bool logResult, ICollection<ResultBase> invalidHandler)
        {
            var flag = false;

            if (slotAttribute.OnOpening == string.Empty &&
                slotAttribute.OnOpened == string.Empty &&
                (slotAttribute.OnClosed == string.Empty &&
                 slotAttribute.OnRegistering == string.Empty) &&
                (slotAttribute.OnRegistered == string.Empty &&
                 slotAttribute.OnDeregistered == string.Empty &&
                 (slotAttribute.OnPlugging == string.Empty &&
                  slotAttribute.OnPlugged == string.Empty)) &&
                slotAttribute.OnUnplugged == string.Empty &&
                slotAttribute.OnSelectionChanged == string.Empty)
                eventHandlerMethodInfosSet = true;
            else
            {
                var type = extensionTypeInfo.type;

                if (!IsReflectionOnly && !eventHandlerMethodInfosSet)
                    flag = true;

                var slotInfos = new SlotInfo[extensionTypeInfo.extensionInfos.Count];

                if (flag)
                {
                    eventHandlerMethodInfosSet = true;

                    for (var i = 0; i < slotInfos.Length; ++i)
                        slotInfos[i] = extensionTypeInfo.extensionInfos[i].slotInfos[Name];
                }

                if (slotAttribute.OnOpening != string.Empty)
                {
                    var implementingMethod = slotAttribute.OnOpening;
                    var mismatchInfo =
                        invalidHandler != null
                            ? new List<IEnumerable<HandlerParameterInfo>>()
                            : null;

                    MiOnOpening =
                        ExtensionTypeInfo.VerifyEventHandlerMethod(
                            type,
                            slotAttribute.OnOpening,
                            Runtime.cancelSlotEventHandlerParamTypes,
                            string.Format(
                                Messages.SlotEventHandlerMethodDesc,
                                "OnOpening",
                                Name),
                            logResult,
                            IsReflectionOnly,
                            mismatchInfo);

                    if (MiOnOpening == null)
                    {
                        var slotTypeInfo = this;
                        var state = (long)(slotTypeInfo.qualificationState |
                            QualificationState.SlotOnOpeningMethodNotFound);

                        slotTypeInfo.qualificationState = (QualificationState)state;

                        if (mismatchInfo != null && mismatchInfo.Count > 0)
                            mismatchInfo.ForEach(
                                hm => invalidHandler.Add(
                                    new InvalidHandlerParameter(this, "OnOpening", implementingMethod, hm)));
                        else if (mismatchInfo != null)
                            invalidHandler.Add(
                                new MissingHandler(this, "OnOpening", implementingMethod));
                    }
                    else if (flag)
                        foreach (var slotInfo in slotInfos)
                            slotInfo.Opening +=
                                new ReflectionEventHandler(
                                    slotInfo.extensionInfo.Object, MiOnOpening).InvokeMethod;
                }

                if (slotAttribute.OnOpened != string.Empty)
                {
                    var implementingMethod = slotAttribute.OnOpened;
                    var mismatchInfo =
                        invalidHandler != null
                            ? new List<IEnumerable<HandlerParameterInfo>>()
                            : null;

                    MiOnOpened =
                        ExtensionTypeInfo.VerifyEventHandlerMethod(
                            type,
                            slotAttribute.OnOpened,
                            Runtime.slotEventHandlerParamTypes,
                            string.Format(
                                Messages.SlotEventHandlerMethodDesc,
                                "OnOpened",
                                Name),
                            logResult,
                            IsReflectionOnly,
                            mismatchInfo);

                    if (MiOnOpened == null)
                    {
                        var slotTypeInfo = this;
                        var state = (long)(slotTypeInfo.qualificationState |
                            QualificationState.SlotOnOpenedMethodNotFound);

                        slotTypeInfo.qualificationState = (QualificationState)state;

                        if (mismatchInfo != null && mismatchInfo.Count > 0)
                            mismatchInfo.ForEach(
                                hm => invalidHandler.Add(
                                    new InvalidHandlerParameter(this, "OnOpened", implementingMethod, hm)));
                        else if (mismatchInfo != null)
                            invalidHandler.Add(
                                new MissingHandler(this, "OnOpened", implementingMethod));
                    }
                    else if (flag)
                        foreach (var slotInfo in slotInfos)
                            slotInfo.Opened +=
                                new ReflectionEventHandler(
                                    slotInfo.extensionInfo.Object, MiOnOpened).InvokeMethod;
                }

                if (slotAttribute.OnClosing != string.Empty)
                {
                    var implementingMethod = slotAttribute.OnClosing;
                    var mismatchInfo =
                        invalidHandler != null
                            ? new List<IEnumerable<HandlerParameterInfo>>()
                            : null;

                    MiOnClosing =
                        ExtensionTypeInfo.VerifyEventHandlerMethod(
                            type,
                            slotAttribute.OnClosing,
                            Runtime.cancelSlotEventHandlerParamTypes,
                            string.Format(
                                Messages.SlotEventHandlerMethodDesc,
                                "OnClosing",
                                Name),
                            logResult,
                            IsReflectionOnly,
                            mismatchInfo);

                    if (MiOnClosing == null)
                    {
                        var slotTypeInfo = this;
                        var state = (long)(slotTypeInfo.qualificationState |
                            QualificationState.SlotOnClosingMethodNotFound);

                        slotTypeInfo.qualificationState = (QualificationState)state;

                        if (mismatchInfo != null && mismatchInfo.Count > 0)
                            mismatchInfo.ForEach(
                                hm => invalidHandler.Add(
                                    new InvalidHandlerParameter(this, "OnClosing", implementingMethod, hm)));
                        else if (mismatchInfo != null)
                            invalidHandler.Add(
                                new MissingHandler(this, "OnClosing", implementingMethod));
                    }
                    else if (flag)
                        foreach (var slotInfo in slotInfos)
                            slotInfo.Closing +=
                                new ReflectionEventHandler(
                                    slotInfo.extensionInfo.Object, MiOnClosing).InvokeMethod;
                }

                if (slotAttribute.OnClosed != string.Empty)
                {
                    var implementingMethod = slotAttribute.OnClosed;
                    var mismatchInfo =
                        invalidHandler != null
                            ? new List<IEnumerable<HandlerParameterInfo>>()
                            : null;

                    MiOnClosed =
                        ExtensionTypeInfo.VerifyEventHandlerMethod(
                            type,
                            slotAttribute.OnClosed,
                            Runtime.slotEventHandlerParamTypes,
                            string.Format(
                                Messages.SlotEventHandlerMethodDesc,
                                "OnClosed",
                                Name),
                            logResult,
                            IsReflectionOnly,
                            mismatchInfo);

                    if (MiOnClosed == null)
                    {
                        var slotTypeInfo = this;
                        var state = (long)(slotTypeInfo.qualificationState |
                            QualificationState.SlotOnClosedMethodNotFound);

                        slotTypeInfo.qualificationState = (QualificationState)state;

                        if (mismatchInfo != null && mismatchInfo.Count > 0)
                            mismatchInfo.ForEach(
                                hm =>
                                invalidHandler.Add(
                                    new InvalidHandlerParameter(this, "OnClosed", implementingMethod, hm)));
                        else if (mismatchInfo != null)
                            invalidHandler.Add(
                                new MissingHandler(this, "OnClosed", implementingMethod));
                    }
                    else if (flag)
                        foreach (var slotInfo in slotInfos)
                            slotInfo.Closed +=
                                new ReflectionEventHandler(
                                    slotInfo.extensionInfo.Object, MiOnClosed).InvokeMethod;
                }

                if (slotAttribute.OnRegistering != string.Empty)
                {
                    var implementingMethod = slotAttribute.OnRegistering;
                    var mismatchInfo =
                        invalidHandler != null
                            ? new List<IEnumerable<HandlerParameterInfo>>()
                            : null;

                    MiOnRegistering =
                        ExtensionTypeInfo.VerifyEventHandlerMethod(
                            type,
                            slotAttribute.OnRegistering,
                            Runtime.cancelRegisterEventHandlerParamTypes,
                            string.Format(
                                Messages.SlotEventHandlerMethodDesc,
                                "OnRegistering",
                                Name),
                            logResult,
                            IsReflectionOnly,
                            mismatchInfo);

                    if (MiOnRegistering == null)
                    {
                        var slotTypeInfo = this;
                        var state = (long)(slotTypeInfo.qualificationState |
                            QualificationState.SlotOnRegisteringMethodNotFound);

                        slotTypeInfo.qualificationState = (QualificationState)state;

                        if (mismatchInfo != null && mismatchInfo.Count > 0)
                            mismatchInfo.ForEach(
                                hm => invalidHandler.Add(
                                    new InvalidHandlerParameter(this, "OnRegistering", implementingMethod, hm)));
                        else if (mismatchInfo != null)
                            invalidHandler.Add(
                                new MissingHandler(this, "OnRegistering", implementingMethod));
                    }
                    else if (flag)
                        foreach (var slotInfo in slotInfos)
                            slotInfo.Registering +=
                                new ReflectionEventHandler(
                                    slotInfo.extensionInfo.Object, MiOnRegistering).InvokeMethod;
                }

                if (slotAttribute.OnRegistered != string.Empty)
                {
                    var implementingMethod = slotAttribute.OnRegistered;
                    var mismatchInfo =
                        invalidHandler != null
                            ? new List<IEnumerable<HandlerParameterInfo>>()
                            : null;

                    MiOnRegistered =
                        ExtensionTypeInfo.VerifyEventHandlerMethod(
                            type,
                            slotAttribute.OnRegistered,
                            Runtime.registerEventHandlerParamTypes,
                            string.Format(
                                Messages.SlotEventHandlerMethodDesc,
                                "OnRegistered",
                                Name),
                            logResult,
                            IsReflectionOnly,
                            mismatchInfo);

                    if (MiOnRegistered == null)
                    {
                        var slotTypeInfo = this;
                        var state = (long)(slotTypeInfo.qualificationState |
                            QualificationState.SlotOnRegisteredMethodNotFound);

                        slotTypeInfo.qualificationState = (QualificationState)state;

                        if (mismatchInfo != null && mismatchInfo.Count > 0)
                            mismatchInfo.ForEach(
                                hm => invalidHandler.Add(
                                    new InvalidHandlerParameter(this, "OnRegistered", implementingMethod, hm)));
                        else if (mismatchInfo != null)
                            invalidHandler.Add(
                                new MissingHandler(this, "OnRegistered", implementingMethod));
                    }
                    else if (flag)
                        foreach (var slotInfo in slotInfos)
                            slotInfo.Registered +=
                                new ReflectionEventHandler(
                                    slotInfo.extensionInfo.Object, MiOnRegistered).InvokeMethod;
                }

                if (slotAttribute.OnDeregistering != string.Empty)
                {
                    var implementingMethod = slotAttribute.OnDeregistering;
                    var mismatchInfo =
                        invalidHandler != null
                            ? new List<IEnumerable<HandlerParameterInfo>>()
                            : null;

                    MiOnDeregistering =
                        ExtensionTypeInfo.VerifyEventHandlerMethod(
                            type,
                            slotAttribute.
                                OnDeregistering,
                            Runtime.cancelRegisterEventHandlerParamTypes,
                            string.Format(
                                Messages.SlotEventHandlerMethodDesc,
                                "OnDeregistering",
                                Name),
                            logResult,
                            IsReflectionOnly,
                            mismatchInfo);

                    if (MiOnDeregistering == null)
                    {
                        var slotTypeInfo = this;
                        var state = (long)(slotTypeInfo.qualificationState |
                            QualificationState.SlotOnDeregisteringMethodNotFound);

                        slotTypeInfo.qualificationState = (QualificationState)state;

                        if (mismatchInfo != null && mismatchInfo.Count > 0)
                            mismatchInfo.ForEach(
                                hm => invalidHandler.Add(
                                    new InvalidHandlerParameter(this, "OnDeregistering", implementingMethod, hm)));
                        else if (mismatchInfo != null)
                            invalidHandler.Add(
                                new MissingHandler(this, "OnDeregistering", implementingMethod));
                    }
                    else if (flag)
                        foreach (var slotInfo in slotInfos)
                            slotInfo.Deregistering +=
                                new ReflectionEventHandler(
                                    slotInfo.extensionInfo.Object, MiOnDeregistering).InvokeMethod;
                }

                if (slotAttribute.OnDeregistered != string.Empty)
                {
                    string implementingMethod = slotAttribute.OnDeregistered;

                    var mismatchInfo =
                        invalidHandler != null
                            ? new List<IEnumerable<HandlerParameterInfo>>()
                            : null;

                    MiOnDeregistered =
                        ExtensionTypeInfo.VerifyEventHandlerMethod(
                            type,
                            slotAttribute.OnDeregistered,
                            Runtime.registerEventHandlerParamTypes,
                            string.Format(
                                Messages.SlotEventHandlerMethodDesc,
                                "OnDeregistered",
                                Name),
                            logResult,
                            IsReflectionOnly,
                            mismatchInfo);

                    if (MiOnDeregistered == null)
                    {
                        var slotTypeInfo = this;
                        var state = (long)(slotTypeInfo.qualificationState |
                            QualificationState.SlotOnDeregisteredMethodNotFound);

                        slotTypeInfo.qualificationState = (QualificationState)state;

                        if (mismatchInfo != null && mismatchInfo.Count > 0)
                            mismatchInfo.ForEach(
                                hm => invalidHandler.Add(
                                    new InvalidHandlerParameter(this, "OnDeregistered", implementingMethod, hm)));
                        else if (mismatchInfo != null)
                            invalidHandler.Add(
                                new MissingHandler(this, "OnDeregistered", implementingMethod));
                    }
                    else if (flag)
                        foreach (var slotInfo in slotInfos)
                            slotInfo.Deregistered +=
                                new ReflectionEventHandler(
                                    slotInfo.extensionInfo.Object, MiOnDeregistered).InvokeMethod;
                }

                if (slotAttribute.OnPlugging != string.Empty)
                {
                    var implementingMethod = slotAttribute.OnPlugging;
                    var mismatchInfo =
                        invalidHandler != null
                            ? new List<IEnumerable<HandlerParameterInfo>>()
                            : null;

                    MiOnPlugging =
                        ExtensionTypeInfo.VerifyEventHandlerMethod(
                            type,
                            slotAttribute.OnPlugging,
                            Runtime.cancelPlugEventHandlerParamTypes,
                            string.Format(
                                Messages.SlotEventHandlerMethodDesc,
                                "OnPlugging",
                                Name),
                            logResult,
                            IsReflectionOnly,
                            mismatchInfo);

                    if (MiOnPlugging == null)
                    {
                        var slotTypeInfo = this;
                        var state = (long)(slotTypeInfo.qualificationState |
                            QualificationState.SlotOnPluggingMethodNotFound);

                        slotTypeInfo.qualificationState = (QualificationState)state;

                        if (mismatchInfo != null && mismatchInfo.Count > 0)
                            mismatchInfo.ForEach(
                                hm => invalidHandler.Add(
                                    new InvalidHandlerParameter(this, "OnPlugging", implementingMethod, hm)));
                        else if (mismatchInfo != null)
                            invalidHandler.Add(
                                new MissingHandler(this, "OnPlugging", implementingMethod));
                    }
                    else if (flag)
                        foreach (var slotInfo in slotInfos)
                            slotInfo.Plugging +=
                                new ReflectionEventHandler(
                                    slotInfo.extensionInfo.Object, MiOnPlugging).InvokeMethod;
                }

                if (slotAttribute.OnPluggingCanceled != string.Empty)
                {
                    var implementingMethod = slotAttribute.OnPluggingCanceled;

                    var mismatchInfo =
                        invalidHandler != null
                            ? new List<IEnumerable<HandlerParameterInfo>>()
                            : null;

                    MiOnPluggingCanceled =
                        ExtensionTypeInfo.VerifyEventHandlerMethod(
                            type,
                            slotAttribute.OnPluggingCanceled,
                            Runtime.cancelPlugEventHandlerParamTypes,
                            string.Format(
                                Messages.SlotEventHandlerMethodDesc,
                                "OnPluggingCanceled",
                                Name),
                            logResult,
                            IsReflectionOnly,
                            mismatchInfo);

                    if (MiOnPluggingCanceled == null)
                    {
                        var slotTypeInfo = this;
                        var state = (long)(slotTypeInfo.qualificationState |
                            QualificationState.SlotOnPluggingCanceledMethodNotFound);

                        slotTypeInfo.qualificationState = (QualificationState)state;

                        if (mismatchInfo != null && mismatchInfo.Count > 0)
                            mismatchInfo.ForEach(
                                hm => invalidHandler.Add(
                                    new InvalidHandlerParameter(this, "OnPluggingCanceled", implementingMethod, hm)));
                        else if (mismatchInfo != null)
                            invalidHandler.Add(
                                new MissingHandler(this, "OnPluggingCanceled", implementingMethod));
                    }
                    else if (flag)
                        foreach (var slotInfo in slotInfos)
                            slotInfo.PluggingCanceled +=
                                new ReflectionEventHandler(
                                    slotInfo.extensionInfo.Object, MiOnPluggingCanceled).InvokeMethod;
                }

                if (slotAttribute.OnPlugged != string.Empty)
                {
                    var implementingMethod = slotAttribute.OnPlugged;

                    var mismatchInfo =
                        invalidHandler != null
                            ? new List<IEnumerable<HandlerParameterInfo>>()
                            : null;

                    MiOnPlugged =
                        ExtensionTypeInfo.VerifyEventHandlerMethod(
                            type,
                            slotAttribute.OnPlugged,
                            Runtime.plugEventHandlerParamTypes,
                            string.Format(
                                Messages.SlotEventHandlerMethodDesc,
                                "OnPlugged",
                                Name),
                            logResult,
                            IsReflectionOnly,
                            mismatchInfo);

                    if (MiOnPlugged == null)
                    {
                        var slotTypeInfo = this;
                        var state = (long)(slotTypeInfo.qualificationState |
                            QualificationState.SlotOnPluggedMethodNotFound);

                        slotTypeInfo.qualificationState = (QualificationState)state;

                        if (mismatchInfo != null && mismatchInfo.Count > 0)
                            mismatchInfo.ForEach(
                                hm => invalidHandler.Add(
                                    new InvalidHandlerParameter(this, "OnPlugged", implementingMethod, hm)));
                        else if (mismatchInfo != null)
                            invalidHandler.Add(
                                new MissingHandler(this, "OnPlugged", implementingMethod));
                    }
                    else if (flag)
                        foreach (SlotInfo slotInfo in slotInfos)
                            slotInfo.Plugged +=
                                new ReflectionEventHandler(
                                    slotInfo.extensionInfo.Object, MiOnPlugged).InvokeMethod;
                }

                if (slotAttribute.OnUnplugging != string.Empty)
                {
                    var implementingMethod = slotAttribute.OnUnplugging;

                    var mismatchInfo =
                        invalidHandler != null
                            ? new List<IEnumerable<HandlerParameterInfo>>()
                            : null;

                    MiOnUnplugging =
                        ExtensionTypeInfo.VerifyEventHandlerMethod(
                            type,
                            slotAttribute.OnUnplugging,
                            Runtime.cancelPlugEventHandlerParamTypes,
                            string.Format(
                                Messages.SlotEventHandlerMethodDesc,
                                "OnUnplugging",
                                Name),
                            logResult,
                            IsReflectionOnly,
                            mismatchInfo);

                    if (MiOnUnplugging == null)
                    {
                        var slotTypeInfo = this;
                        var state = (long)(slotTypeInfo.qualificationState |
                            QualificationState.SlotOnUnpluggingMethodNotFound);

                        slotTypeInfo.qualificationState = (QualificationState)state;

                        if (mismatchInfo != null && mismatchInfo.Count > 0)
                            mismatchInfo.ForEach(
                                hm => invalidHandler.Add(
                                    new InvalidHandlerParameter(this, "OnUnplugging", implementingMethod, hm)));
                        else if (mismatchInfo != null)
                            invalidHandler.Add(
                                new MissingHandler(this, "OnUnplugging", implementingMethod));
                    }
                    else if (flag)
                        foreach (var slotInfo in slotInfos)
                            slotInfo.Unplugging +=
                                new ReflectionEventHandler(
                                    slotInfo.extensionInfo.Object, MiOnUnplugging).InvokeMethod;
                }

                if (slotAttribute.OnUnplugged != string.Empty)
                {
                    var implementingMethod = slotAttribute.OnUnplugged;

                    var mismatchInfo =
                        invalidHandler != null
                            ? new List<IEnumerable<HandlerParameterInfo>>()
                            : null;

                    MiOnUnplugged =
                        ExtensionTypeInfo.VerifyEventHandlerMethod(
                            type,
                            slotAttribute.OnUnplugged,
                            Runtime.plugEventHandlerParamTypes,
                            string.Format(
                                Messages.SlotEventHandlerMethodDesc,
                                "OnUnplugged",
                                Name),
                            logResult,
                            IsReflectionOnly,
                            mismatchInfo);

                    if (MiOnUnplugged == null)
                    {
                        var slotTypeInfo = this;
                        var state =
                            (long)(slotTypeInfo.qualificationState |
                            QualificationState.SlotOnUnpluggedMethodNotFound);

                        slotTypeInfo.qualificationState = (QualificationState)state;

                        if (mismatchInfo != null && mismatchInfo.Count > 0)
                            mismatchInfo.ForEach(
                                hm => invalidHandler.Add(
                                    new InvalidHandlerParameter(this, "OnUnplugged", implementingMethod, hm)));
                        else if (mismatchInfo != null)
                            invalidHandler.Add(
                                new MissingHandler(this, "OnUnplugged", implementingMethod));
                    }
                    else if (flag)
                        foreach (var slotInfo in slotInfos)
                            slotInfo.Unplugged +=
                                new ReflectionEventHandler(
                                    slotInfo.extensionInfo.Object, MiOnUnplugged).InvokeMethod;
                }

                if (slotAttribute.OnSelectionChanged != string.Empty)
                {
                    var implementingMethod = slotAttribute.OnSelectionChanged;

                    var mismatchInfo =
                        invalidHandler != null
                            ? new List<IEnumerable<HandlerParameterInfo>>()
                            : null;

                    MiOnSelectionChanged =
                        ExtensionTypeInfo.VerifyEventHandlerMethod(
                            type,
                            slotAttribute.OnSelectionChanged,
                            Runtime.selectionChangedHandlerParamTypes,
                            string.Format(
                                Messages.SlotEventHandlerMethodDesc,
                                "OnSelectionChanged",
                                Name),
                            logResult,
                            IsReflectionOnly,
                            mismatchInfo);

                    if (MiOnSelectionChanged == null)
                    {
                        var slotTypeInfo = this;
                        var state = (long)(slotTypeInfo.qualificationState |
                            QualificationState.SlotOnSelectionChangedMethodNotFound);

                        slotTypeInfo.qualificationState = (QualificationState)state;

                        if (mismatchInfo != null && mismatchInfo.Count > 0)
                            mismatchInfo.ForEach(
                                hm => invalidHandler.Add(
                                    new InvalidHandlerParameter(this, "OnSelectionChanged", implementingMethod, hm)));
                        else if (mismatchInfo != null)
                            invalidHandler.Add(
                                new MissingHandler(this, "OnSelectionChanged", implementingMethod));
                    }
                    else if (flag)
                        foreach (var slotInfo in slotInfos)
                            slotInfo.SelectionChanged +=
                                new ReflectionEventHandler(
                                    slotInfo.extensionInfo.Object, MiOnSelectionChanged).InvokeMethod;
                }
            }

            var slotType = this;
            var stats = (long)(slotType.qualificationState & ~QualificationState.MethodQualificationMissing);
            slotType.qualificationState = (QualificationState)stats;
            return qualificationState;
        }

        internal void OnOpening(object sender, CancelSlotEventArgs args)
        {
            if (Opening == null)
                return;

            Runtime.InvokeCancelEventHandler(
                string.Format(
                    Messages.SlotEventHandlerMethodDesc,
                    "Opening",
                    Name),
                Opening,
                sender,
                args);
        }

        internal void OnOpened(object sender, SlotEventArgs args)
        {
            if (Opened == null)
                return;

            Runtime.InvokeEventHandler(
                string.Format(
                    Messages.SlotEventHandlerMethodDesc,
                    "Opened",
                    Name),
                Opened,
                sender,
                args);
        }

        internal void OnClosing(object sender, CancelSlotEventArgs args)
        {
            if (Closing == null)
                return;

            Runtime.InvokeCancelEventHandler(
                string.Format(
                    Messages.SlotEventHandlerMethodDesc,
                    "Closing",
                    Name),
                Closing,
                sender,
                args);
        }

        internal void OnClosed(object sender, SlotEventArgs args)
        {
            if (Closed == null)
                return;

            Runtime.InvokeEventHandler(
                string.Format(
                    Messages.SlotEventHandlerMethodDesc,
                    "Closed",
                    Name),
                Closed,
                sender,
                args);
        }

        internal void OnRegistering(object sender, CancelRegisterEventArgs args)
        {
            if (Registering == null)
                return;

            Runtime.InvokeCancelEventHandler(
                string.Format(
                    Messages.SlotEventHandlerMethodDesc,
                    "Registering",
                    Name),
                Registering,
                sender,
                args);
        }

        internal void OnRegistered(object sender, RegisterEventArgs args)
        {
            if (Registered == null)
                return;

            Runtime.InvokeEventHandler(
                string.Format(
                    Messages.SlotEventHandlerMethodDesc,
                    "Registered",
                    Name),
                Registered,
                sender,
                args);
        }

        internal void OnDeregistering(object sender, CancelRegisterEventArgs args)
        {
            if (Deregistering == null)
                return;

            Runtime.InvokeCancelEventHandler(
                string.Format(
                    Messages.SlotEventHandlerMethodDesc,
                    "Deregistering",
                    Name),
                Deregistering,
                sender,
                args);
        }

        internal void OnDeregistered(object sender, RegisterEventArgs args)
        {
            if (Deregistered == null)
                return;

            Runtime.InvokeEventHandler(
                string.Format(
                    Messages.SlotEventHandlerMethodDesc,
                    "Deregistered",
                    Name),
                Deregistered,
                sender,
                args);
        }

        internal void OnPlugging(object sender, CancelPlugEventArgs args)
        {
            if (Plugging == null)
                return;

            Runtime.InvokeCancelEventHandler(
                string.Format(
                    Messages.SlotEventHandlerMethodDesc,
                    "Plugging",
                    Name),
                Plugging,
                sender,
                args);
        }

        internal void OnPluggingCanceled(object sender, CancelPlugEventArgs args)
        {
            if (PluggingCanceled == null)
                return;

            Runtime.InvokeCancelEventHandler(
                string.Format(
                    Messages.SlotEventHandlerMethodDesc,
                    "PluggingCanceled",
                    Name),
                PluggingCanceled,
                sender,
                args);
        }

        internal void OnPlugged(object sender, PlugEventArgs args)
        {
            if (Plugged == null)
                return;

            Runtime.InvokeEventHandler(
                string.Format(
                    Messages.SlotEventHandlerMethodDesc,
                    "Plugged",
                    Name),
                Plugged,
                sender,
                args);
        }

        internal void OnUnplugging(object sender, CancelPlugEventArgs args)
        {
            if (Unplugging == null)
                return;

            Runtime.InvokeCancelEventHandler(
                string.Format(
                    Messages.SlotEventHandlerMethodDesc,
                    "Unplugging",
                    Name),
                Unplugging,
                sender,
                args);
        }

        internal void OnUnplugged(object sender, PlugEventArgs args)
        {
            if (Unplugged == null)
                return;

            Runtime.InvokeEventHandler(
                string.Format(
                    Messages.SlotEventHandlerMethodDesc,
                    "Unplugged",
                    Name),
                Unplugged,
                sender,
                args);
        }

        internal void OnSelectionChanged(object sender, SelectionChangedEventArgs args)
        {
            if (SelectionChanged == null)
                return;

            Runtime.InvokeEventHandler(
                string.Format(
                    Messages.SlotEventHandlerMethodDesc,
                    "SelectionChanged",
                    Name),
                SelectionChanged,
                sender,
                args);
        }
    }
}

